#include <illib/Exception.h>
#include <illib/System.h>
#include <illib/Log.h>
#include "Type.h"
#include "Runtime.h"

namespace ilrt {
	BasicPointer::BasicPointer() : value_(0) {}
	BasicPointer::BasicPointer(void * value) : value_(value) {}
	BasicPointer::BasicPointer(const BasicPointer &value) : value_(value.value_) {}
	BasicTypedPointer::BasicTypedPointer() : BasicPointer(NULL), type_(0) {}
	BasicTypedPointer::BasicTypedPointer(void * value) : BasicPointer(value), type_(0) {}
	BasicTypedPointer::BasicTypedPointer(const BasicPointer &value) : BasicPointer(value), type_(0) {}
	BasicTypedPointer::BasicTypedPointer(void * value, BasicType &type)  : BasicPointer(value), type_(&type) {}
	BasicTypedPointer::BasicTypedPointer(const BasicPointer &value, BasicType &type)  : BasicPointer(value), type_(&type) {}
	BasicTypedPointer::BasicTypedPointer(const BasicTypedPointer &value) : BasicPointer(value), type_(value.type_) {}
	BasicType::~BasicType(){

	}

	BasicType & BasicPointer::_type(){
		Runtime & rt = runtime();
		if(isValue()){
			if (value_ == 0) return rt.types.Undefined;
			if (value_ == &reserved_[0]) return rt.types.None;
			if ((value_ == &reserved_[1]) || (value_ == &reserved_[2])) return rt.types.Boolean;
			if ((reinterpret_cast<uintptr_t>(value_) >= reinterpret_cast<uintptr_t>(&reserved_[3])) &&
					(reinterpret_cast<uintptr_t>(value_) <= reinterpret_cast<uintptr_t>(&reserved_[3+255]))) return rt.types.UnsignedInt8;
			if ((reinterpret_cast<uintptr_t>(value_) >= reinterpret_cast<uintptr_t>(&reserved_[3+256])) &&
					(reinterpret_cast<uintptr_t>(value_) <= reinterpret_cast<uintptr_t>(&reserved_[3+256+255]))) return rt.types.SignedInt8;
		}
		illib::MemoryTracker::Tracked *entry = illib::MemoryTracker::tracker().entry(value_);
		assert(entry);
		assert(entry->allocator());
		illib::Allocator * root = entry->allocator()->root();
		assert(root);
		void * data = root->data();
		assert(data);
		BasicType * type = static_cast<BasicType*>(data);
		return *type;
	}
	BasicTypedPointer BasicPointer::_typed(){
		return BasicTypedPointer(value_, _type());
	}
	void BasicPointer::destroy(){
		BasicTypedPointer t = _typed();
		t.destroy();
	}

	BasicType & BasicTypedPointer::_type(){
		if(!type_) type_ = &BasicPointer::_type();
		return *type_;
	}

	BasicPointer BasicPointer::Undefined(reinterpret_cast<void *>(0));
	BasicPointer BasicPointer::None(&reserved_[0]);
	BasicPointer BasicPointer::True(&reserved_[1]);
	BasicPointer BasicPointer::False(&reserved_[2]);
	char BasicPointer::reserved_[4+256+256];
};

